import user  # look for .pythonrc.py for user init
import math
import ROOT
import PyCintex
import AthenaROOTAccess.transientTree


##############################################################################
#
# Begining of SoftEelctron 
#

class SoftElectron:
    def __init__(self):
        self.runNo                  = 0
        self.hists                  = {}
        self.fDeltaRCut             = 0.3
        self.fEtaCut                = 2.5
        
        self.fSoftElectrons         = []
        self.fHardElectrons         = []

        self.fSoftElMatchedSignal   = 0 
        self.fSoftElMatchedBkgrnd   = 0

        self.fBElectronlist         = []
        self.fCElectronlist         = []

        self.fMEBQuarkList          = []
        self.fMECQuarkList          = []

        self.fBHadronList           = []
        self.fCHadronList           = []


    '''Utility function to loop over the containers'''
    def toiter (self,beg, end):
        while beg != end:
            yield beg.__deref__()
            beg.__preinc__()
        return

    ''' Utility function HeP LorentzVector to TLorentzVector '''
    def GetTLV(self,p):
        tlv = ROOT.TLorentzVector()
        hlv = p.momentum()
        tlv.SetPtEtaPhiM(hlv.perp(),hlv.eta(),hlv.phi(),hlv.m())

        return tlv

    '''Utility function floating point range'''
    def drange(self,start, stop, step):
        r = start
        while r < stop:
            yield r
            r += step


    '''Book the Histograms and anything and everything 
    that you want to do before you start the analysis'''
    def initialize(self):
        '''Book histograms'''
        self.hists["nEl"]       = ROOT.TH1F("nEl","Electron Multiplictiy",50,0,50)
        self.hists["ElPt"]      = ROOT.TH1F("ElPt","Electron P_{t}; [GeV]",500,0,500)
        self.hists["ElEta"]     = ROOT.TH1F("ElEta","Electron #eta",80,-4,4)
        self.hists["ElPhi"]     = ROOT.TH1F("ElPhi","Electron #phi",80,-4,4)

        self.hists["nSoftEl"]   = ROOT.TH1F("nSoftEl","# soft electrons",10,0,10)
        self.hists["softElPt"]  = ROOT.TH1F("softElPt","soft electron p_{t};[GeV]",250,0,25)
        self.hists["softElEta"] = ROOT.TH1F("softElEta","soft electron #eta",80,-4,4)
        self.hists["softElPhi"] = ROOT.TH1F("softElPhi","soft electron #phi",80,-4,4)

        self.hists["nHardEl"]   = ROOT.TH1F("nHardEl","# hard electrons",10,0,10)
        self.hists["hardElPt"]  = ROOT.TH1F("hardElPt","hard electron p_{t};[GeV]",500,0,500)
        self.hists["hardElEta"] = ROOT.TH1F("hardElEta","hard electron #eta",80,-4,4)
        self.hists["hardElPhi"] = ROOT.TH1F("hardElPhi","hard electron #phi",80,-4,4)

        self.hists["bElectronPt"]   = ROOT.TH1F("bElectronPt","BHadron Decay electron p_{T}; [GeV]",500,0,500)
        self.hists["cElectronPt"]   = ROOT.TH1F("cElectronPt","CHadron Decay electron p_{T}; [GeV]",500,0,500)
        self.hists["bElectronEta"]  = ROOT.TH1F("bElectronEta","BHadron Decay electron #eta",100,-5,5)
        self.hists["cElectronEta"]  = ROOT.TH1F("cElectronEta","CHadron Decay electron #eta",80,-4,4)
        self.hists["bElectronPhi"]  = ROOT.TH1F("bElectronPhi","BHadron Decay electron #varphi",100,-5,5)
        self.hists["cElectronPhi"]  = ROOT.TH1F("cElectronPhi","CHadron Decay electron #varphi",80,-4,4)

        self.hists["bHadronPdg"]= ROOT.TH1F("bHadronPdg","BHadron PDG",10000,-5000,5000)
        self.hists["bHadronPt"] = ROOT.TH1F("bHadronPt","BHadron p_{T}; [GeV]",500,0,500)
        self.hists["bHadronEta"]= ROOT.TH1F("bHadronEta","BHadron #eta",100,-5,5)
        self.hists["bHadronPhi"]= ROOT.TH1F("bHadronPhi","BHadron #varphi",80,-4,4)

        self.hists["matched_bHadronPt"] = ROOT.TH1F("matched_bHadronPt","Electron matched B Hadron p_{T}; [GeV]",500,0,500)
        self.hists["matched_bHadronEta"]= ROOT.TH1F("matched_bHadronEta","Electron matched B Hadron #eta",100,-5,5)
        self.hists["matched_bHadronPhi"]= ROOT.TH1F("matched_bHadronPhi","Electron matched B Hadron #varphi",80,-4,4)

        self.hists["cHadronPdg"]= ROOT.TH1F("cHadronPdg","CHadron PDG",10000,-5000,5000)
        self.hists["cHadronPt"] = ROOT.TH1F("cHadronPt","CHadron p_{T}; [GeV]",500,0,500)
        self.hists["cHadronEta"]= ROOT.TH1F("cHadronEta","CHadron #eta",100,-5,5)
        self.hists["cHadronPhi"]= ROOT.TH1F("cHadronPhi","CHadron #varphi",80,-4,4)

        self.hists["matched_cHadronPt"] = ROOT.TH1F("matched_cHadronPt","Electron matched C Hadron p_{T}; [GeV]",500,0,500)
        self.hists["matched_cHadronEta"]= ROOT.TH1F("matched_cHadronEta","Electron matched C Hadron #eta",100,-5,5)
        self.hists["matched_cHadronPhi"]= ROOT.TH1F("matched_cHadronPhi","Electron matched C Hadron #varphi",80,-4,4)

        self.hists["MEbQuarkPt"]  = ROOT.TH1F("MEbQuarkPt","b Quark p_{T}; [GeV]",500,0,500)
        self.hists["MEbQuarkEta"] = ROOT.TH1F("MEbQuarkEta","b Quark #eta",100,-5,5)
        self.hists["MEbQuarkPhi"] = ROOT.TH1F("MEbQuarkPhi","b Quark #varphi",80,-4,4)

        self.hists["matched_bQuarkPt"]  = ROOT.TH1F("matched_bQuarkPt","Electron matched b Quark p_{T}; [GeV]",500,0,500)
        self.hists["matched_bQuarkEta"] = ROOT.TH1F("matched_bQuarkEta","Electron matched bQuark #eta",100,-5,5)
        self.hists["matched_bQuarkPhi"] = ROOT.TH1F("matched_bQuarkPhi","Electron matched bQuark #varphi",80,-4,4)

        self.hists["MEcQuarkPt"]  = ROOT.TH1F("MEcQuarkPt","c Quark p_{T}; [GeV]",500,0,500)
        self.hists["MEcQuarkEta"] = ROOT.TH1F("MEcQuarkEta","c Quark #eta; [GeV]",100,-5,5)
        self.hists["MEcQuarkPhi"] = ROOT.TH1F("MEcQuarkPhi","c Quark #varphi; [GeV]",100,-4,4)

        self.hists["matched_cQuarkPt"]  = ROOT.TH1F("matched_cQuarkPt","Electron matched c Quark p_{T}; [GeV]",500,0,500)
        self.hists["matched_cQuarkEta"] = ROOT.TH1F("matched_cQuarkEta","Electron matched c Quark #eta",100,-5,5)
        self.hists["matched_cQuarkPhi"] = ROOT.TH1F("matched_cQuarkPhi","Electron matched c Quark #varphi",80,-4,4)

        self.hists["nBEventsGen"]           = ROOT.TH1F("nBEventsGen","# B Events Generated (parent b quark hard)",4,0,4)
        self.hists["nBEventsMatched"]       = ROOT.TH1F("nBEventsMatched","#B Events with a Match to atleast one B Hadron",4,0,4)
        self.hists["nBEventsSemileptGen"]   = ROOT.TH1F("nBEventsSemileptGen"," # B Events Generated Semileptonic(electron)",4,0,4)

        self.hists["nBEventsThreeProngAccptd"]  = ROOT.TH1F("nBEventsThreeProngAccptd","# B Events Accepted 3 prong",4,0,4)
        self.hists["nBEventsTrueThreeProng"]    = ROOT.TH1F("nBEventsTrueThreeProng","#B Events True ThreeProng",4,0,4)
        self.hists["nBEventsTwoAndOneAccptd"]   = ROOT.TH1F("nBEventsTwoAndOneAccptd","# B Events (2+1) accepted",4,0,4)
        self.hists["nBEventsFourProngAccptd"]   = ROOT.TH1F("nBEventsFourProngAccptd","#B Events FourProng in acceptance",4,0,4)
        self.hists["nBEventsTwoAndTwoAccptd"]   = ROOT.TH1F("nBEventsTwoAndTwoAccptd","#B Events (2+2) accepted",4,0,4)


        self.hists["nCEventsGen"]           = ROOT.TH1F("nCEventsGen","# C Events Generated (parent c quark hard)",4,0,4)
        self.hists["nCEventsMatched"]       = ROOT.TH1F("nCEventsMatched","# C Events with a match to atleast one C Hadron",4,0,4)
        self.hists["nCEventsSemileptGen"]   = ROOT.TH1F("nCEventsSemileptGen", " # C Events Semileptonic (electron)",4,0,4)

        self.hists["nCEventsThreeProngAccptd"]  = ROOT.TH1F("nCEventsThreeProngAccptd","# C Events  Accepted 3 prong",4,0,4)
        self.hists["nCEventsTrueThreeProng"]    = ROOT.TH1F("nCEventsTrueThreeProng","#C Events True ThreeProng",4,0,4)
        self.hists["nCEventsTwoAndOneAccptd"]   = ROOT.TH1F("nCEventsTwoAndOneAccptd","# C Events Accepted (2+1)",4,0,4)
        self.hists["nCEventsFourProngAccptd"]   = ROOT.TH1F("nCEventsFourProngAccptd","# C Events  Four Prong acceptence",4,0,4)
        self.hists["nCEventsTwoAndTwoAccptd"]   = ROOT.TH1F("nCEventsTwoAndTwoAccptd","# C Events  Accepted (2+2)",4,0,4)

        self.hists["nOtherEventsThreeProngAccptd"]  = ROOT.TH1F("nOtherEventsThreeProngAccptd","nOtherEventsThreeProngAccptd",4,0,4)
        self.hists["nOtherEventsTwoAndOneAccptd"]   = ROOT.TH1F("nOtherEventsTwoAndOneAccptd","nOtherEventsTwoAndOneAccptd",4,0,4)
        self.hists["nOtherEventsFourProngAccptd"]   = ROOT.TH1F("nOtherEventsFourProngAccptd","nOtherEventsFourProngAccptd",4,0,4)
        self.hists["nOtherEventsTwoAndTwoAccptd"]   = ROOT.TH1F("nOtherEventsTwoAndTwoAccptd","nOtherEventsTwoAndTwoAccptd",4,0,4)


        self.hists["nHardElSignal"] = ROOT.TH1F("nHardElSignal","# hard electrons signal channel",10,0,10)
        self.hists["nHardElBkgrnd"] = ROOT.TH1F("nHardElBkgrnd","# hard electrons background channel",10,0,10)
        self.hists["nSoftElSignal"] = ROOT.TH1F("nSoftElSignal","# soft electrons signal channel",10,0,10)
        self.hists["nSoftElBkgrnd"] = ROOT.TH1F("nSoftElBkgrnd","# soft electrons background channel",10,0,10)

        '''Acceptance studies'''
        self.hists["deltaR_bQuarkPt"]           = ROOT.TH2F("deltaR_bQuarkPt","deltaR_bQuarkPt; #Delta R_{cut}; Matched Quark Pt [GeV]",101,0,3,1000,0,500)
        self.hists["deltaR_cQuarkPt"]           = ROOT.TH2F("deltaR_cQuarkPt","deltaR_cQuarkPt; #Delta R_{cut}; Matched Quark Pt [GeV]",101,0,3,1000,0,500)


        [myHist.Sumw2() for myHistName, myHist in self.hists.iteritems()]

    '''For Overlap Removal'''
    def SetRunNumber(self,runNo):
        self.runNo = runNo

    '''Reset all the internal containers
    Called during every execute loop'''
    def ResetCounters(self):
        self.fSoftElectrons[:]    = []
        self.fHardElectrons[:]    = []

        self.fBElectronlist[:]    = []
        self.fCElectronlist[:]    = []
        
        self.fMEBQuarkList[:] = []
        self.fMECQuarkList[:] = []

        self.fBHadronList[:]    = []
        self.fCHadronList[:]    = []


    '''Check if the the current particle is a decayed/decaying
    Heavy Flavor Hadron. Status code from Herwig'''
    def IsCHadron(self,p):
        status = p.status()
        mpdg = abs(p.pdg_id())
        if(status == 196 or status == 197): #Direct unstable hadron (From Herwig manual)
            self.fCHadronList += [p]
            return ( ( 400  < mpdg and mpdg < 499 )   or \
                    ( 10400 < mpdg and mpdg < 10499 ) or \
                    (  4000 < mpdg and mpdg < 4999  ) or \
                    ( 20400 < mpdg and mpdg < 20499 ) )
        else:
            return False 

    '''Same as above, this time we check for a B-hadron'''
    def IsBHadron(self,p):
        status = p.status()
        mpdg = abs(p.pdg_id())

        if(status == 196 or status == 197): #Direct unstable hadron (From Herwig manual)
            self.fBHadronList += [p]
            return ( ( 500 < mpdg and mpdg < 599 )    or \
                    ( 10500 < mpdg and mpdg < 10599 )  or \
                    (  5000 < mpdg and mpdg < 5999  )  or \
                    ( 20500 < mpdg and mpdg < 20599 ) )
        else:
            return False

    '''Check if the Hard Quarks from collisions is a B/C Quark
    Status codes from Herwig'''
    def IsMEBCParton(self,p):
        myBool  = False
        apdg    = abs(p.pdg_id())

        '''Production Vertex of the current particle '''
        prodVtx = p.production_vertex()
        if(prodVtx):

            ''' Loop over the parents of the current particle'''
            for parent in self.toiter(prodVtx.particles_in_const_begin(),prodVtx.particles_in_const_end()): 
                '''check if there is no b/c hadron parent'''
                if( not (abs(parent.pdg_id())%10000)/1000 ==  apdg  or (abs(parent.pdg_id())%1000)/100 == apdg):
                    ''' reject c-quarks from a b-quark /hadron decay'''
                    if ( not (apdg == 4 and ( abs(parent.pdg_id() == 5 or  (abs(parent.pdg_id()%10000)/1000 == 5 or (abs(parent.pdg_id())%1000)/100 == 5 ) )))):
                        ''' reject particle with MPI parent '''
                        if( not (abs(parent.pdg_id()) ==0 or parent.status() == 120)): #Herwig specific status codes 
                            if (p.status() == 123 or p.status()==124):
                                myBool = True
            
            if (myBool):
                '''Fill the quark containers '''
                if(apdg == 4):
                    self.fMECQuarkList +=[p]
                elif(apdg == 5):
                    self.fMEBQuarkList +=[p]

        return myBool

    '''Check if the the current particle Does not have 
    a B/C Quark Daughter'''
    def HasNoDaughterBCQuark(self,p):
        myBool = False
        apdg = abs(p.pdg_id())
        '''Daughter Vertex '''
        daughterVtx = p.end_vertex();
        if(daughterVtx):
            for daughter in self.toiter(daughterVtx.particles_out_const_begin(),daughterVtx.particles_out_const_end()):
                '''check there is  atleast one non b/c quark daughters '''
                if(abs(daughter.pdg_id()) != apdg):
                    myBool = True

        return myBool


    '''Check if the Process is Either signal or background'''
    def EventType(self,ev):

        returnString=""

        Ztoee       = False
        MEBParton   = False
        MECParton   = False
        FoundBHadron= False
        FoundBMatch = False
        FoundCHadron= False
        FoundCMatch = False
        HasDaughterElectron=False

        isBB        = True # MANUAL WORKAROUND 
        isCC        = False
        isLight     = False

        if ( (self.runNo >= 106280 and  self.runNo<= 106283) or \
                (self.runNo >= 107280 and  self.runNo<= 107283) ):
            '''Wbb samples'''
            isBB = True 
        
        elif ( (self.runNo >= 109300 and self.runNo <= 109313) or  \
                (self.runNo >= 118962 and self.runNo <= 118965) ): 
            '''Zbb samples'''
            isBB = True
        
        elif ( self.runNo == 116108 ):  #ttbb samples
            isBB = True

        elif ( (self.runNo >= 117284 and self.runNo <= 117287) or  (self.runNo == 116109) ): #ttbar + cc + Np
            isCC = True

        elif( (self.runNo >= 126414 and self.runNo <= 126417)):   #Zee +ccbar sample (Alpgen Jimmy)
            isCC = True

        elif ( (self.runNo >= 107680 and self.runNo <= 107685)      \
                or  (self.runNo >= 107690 and self.runNo <= 107695) \
                or  (self.runNo >= 107700 and self.runNo <= 107705) \
                or  (self.runNo >= 144018 and self.runNo <= 144020) \
                or  (self.runNo >= 144022 and self.runNo <= 144024) \
                or  (self.runNo >= 144196 and self.runNo <= 144207) \
                or  (self.runNo >= 105890 and self.runNo <= 105897) \
                or  (self.runNo >= 117887 and self.runNo <= 117899)):
            ''' W inclusive sample'''
            isLight = True

        elif ( (self.runNo >= 107650 and self.runNo <= 107655)   or \
                (self.runNo >= 107660 and self.runNo <= 107665)  or \
                (self.runNo >= 107670 and self.runNo <= 107675)  or \
                (self.runNo >= 107710 and self.runNo <= 107715)  or \
                (self.runNo >= 144192 and self.runNo <= 144195)  or \
                (self.runNo == 144021)):
            ''' Z inclusive sample'''
            isLight = True


        '''Loop over the GEN_EVENT particle container'''
        for p in self.toiter(ev.particles_begin(), ev.particles_end()):
            '''Find Soft and hard electrons '''
            apdgid = abs(p.pdg_id())
            aeta   = abs(p.momentum().eta())
            status = p.status()
            barcode= p.barcode()
            
            if(apdgid == 11 and status == 1 and aeta <self.fEtaCut):
                elPt    = p.momentum().perp()/1000 #[GeV]
                elEta   = p.momentum().eta()
                elPhi   = p.momentum().phi()
                elBc    = p.barcode()

                self.hists["ElPt"].Fill(elPt)
                self.hists["ElEta"].Fill(elEta)
                self.hists["ElPhi"].Fill(elPhi)

                if(elPt >2 and elPt < 20):
                    self.fSoftElectrons +=[p]
                    self.hists["softElPt"].Fill(elPt)
                    self.hists["softElEta"].Fill(elEta)
                    self.hists["softElPhi"].Fill(elPhi)
                
                else :
                    self.fHardElectrons +=[p]
                    self.hists["hardElPt"].Fill(elPt)
                    self.hists["hardElEta"].Fill(elEta)
                    self.hists["hardElPhi"].Fill(elPhi)
                    
            elif(self.IsMEBCParton(p)):
                '''Find ME b/c partons'''
                if(abs(p.pdg_id()) == 5 and isBB):
                    MEBParton = True
                    self.hists["MEbQuarkPt"].Fill(p.momentum().perp()/1000)
                    self.hists["MEbQuarkEta"].Fill(p.momentum().eta())
                    self.hists["MEbQuarkPhi"].Fill(p.momentum().phi())
                elif(abs(p.pdg_id()) == 4 and isCC):
                    MECParton = True
                    self.hists["MEcQuarkPt"].Fill(p.momentum().perp()/1000)
                    self.hists["MEcQuarkEta"].Fill(p.momentum().eta())
                    self.hists["MEcQuarkPhi"].Fill(p.momentum().phi())

            elif(self.IsBHadron(p)):
                FoundBHadron = True
                self.hists["bHadronPdg"].Fill(p.pdg_id())
                self.hists["bHadronPt"].Fill(p.momentum().perp()/1000)
                self.hists["bHadronEta"].Fill(p.momentum().eta())
                self.hists["bHadronPhi"].Fill(p.momentum().phi())
                
            elif(self.IsCHadron(p)):
                FoundCHadron = True
                self.hists["cHadronPdg"].Fill(p.pdg_id())
                self.hists["cHadronPt"].Fill(p.momentum().perp()/1000)
                self.hists["cHadronEta"].Fill(p.momentum().eta())
                self.hists["cHadronPhi"].Fill(p.momentum().phi())

            '''Make sure Z Decays to ee'''
            Ztoee = True # The mc sample used to Z(ee)

        if(MEBParton  and isBB):
            self.hists["nBEventsGen"].Fill(1)
        elif(MECParton and isCC):
            self.hists["nCEventsGen"].Fill(1)
        elif(MEBParton and MECParton):
            print "FOUND ME B & C Parton : FATAL "

        if(MEBParton and FoundBHadron and \
                not (isCC or isLight)): #Overlap Removal
            '''Acceptance studies'''
            QuarkBCList= []
            DrPtDict    = {}
            for myDr in self.drange(0.1, 2.5, 0.05):
                myIndex_dict = dict([(self.fMEBQuarkList.index(q),self.fBHadronList.index(h)) for q in self.fMEBQuarkList for h  in self.fBHadronList \
                        if math.sqrt((q.momentum().eta() - h.momentum().eta())**2 + (q.momentum().phi() - h.momentum().phi())**2) < myDr])
                if(len(myIndex_dict)):
                    'Found Atleast One match'
                    for q_idx, h_idx in myIndex_dict.iteritems():
                        matchedQuark = self.fMEBQuarkList[q_idx]
                        if( matchedQuark.barcode() in QuarkBCList):
                            break
                        else:
                            QuarkBCList+= [matchedQuark.barcode()]
                            DrPtDict[myDr] = matchedQuark.momentum().mag()/1000
            for dr,pt in DrPtDict.iteritems():
                self.hists["deltaR_bQuarkPt"].Fill(dr,pt)
                break
            #Something is Wrong in the above statemetns.. Needs more investigation 

            '''check if the FourVector of quarks and hadrons match'''
            index_dict = dict([(self.fMEBQuarkList.index(q),self.fBHadronList.index(h)) for q in self.fMEBQuarkList for h  in self.fBHadronList \
                    if math.sqrt((q.momentum().eta() - h.momentum().eta())**2 + (q.momentum().phi() - h.momentum().phi())**2) < self.fDeltaRCut])

            if(len(index_dict)):
                '''Found A Match'''
                FoundBMatch = True
                for q_idx, h_idx in index_dict.iteritems():
                    matchedQuark = self.fMEBQuarkList[q_idx]
                    matchedHadron= self.fBHadronList[h_idx]
                    
                    self.hists["matched_bQuarkPt"].Fill(matchedQuark.momentum().perp()/1000)
                    self.hists["matched_bQuarkEta"].Fill(matchedQuark.momentum().eta())
                    self.hists["matched_bQuarkPhi"].Fill(matchedQuark.momentum().phi())
                    
                    self.hists["matched_bHadronPt"].Fill(matchedHadron.momentum().perp()/1000)
                    self.hists["matched_bHadronEta"].Fill(matchedHadron.momentum().eta())
                    self.hists["matched_bHadronPhi"].Fill(matchedHadron.momentum().phi())

                    endVertex = matchedHadron.end_vertex()
                    if(endVertex):
                        for daughter in self.toiter(endVertex.particles_begin(1),endVertex.particles_end(1)):
                            if(abs(daughter.pdg_id())==11 and daughter.status() ==1):
                                self.fBElectronlist += [daughter]
                                HasDaughterElectron= True

                self.hists["nBEventsGen"].Fill(1)
                if(HasDaughterElectron):
                    self.hists["nBEventsSemileptGen"].Fill(1)
                    returnString = 'signal'


        elif(MECParton and FoundCHadron and \
                not (isBB or isLight)):# Overlap Removal

            '''Acceptance studies'''
            QuarkBCList= []
            DrPtDict    = {}
            for myDr in self.drange(0.1, 2.5, 0.05):
                myIndex_dict = dict([(self.fMECQuarkList.index(q),self.fCHadronList.index(h)) for q in self.fMECQuarkList for h  in self.fCHadronList \
                        if math.sqrt((q.momentum().eta() - h.momentum().eta())**2 + (q.momentum().phi() - h.momentum().phi())**2) < myDr])
                if(len(myIndex_dict)):
                    'Found Atleast One match'
                    for q_idx, h_idx in myIndex_dict.iteritems():
                        matchedQuark = self.fMECQuarkList[q_idx]
                        if( matchedQuark.barcode() in QuarkBCList):
                            break
                        else:
                            QuarkBCList+= [matchedQuark.barcode()]
                            DrPtDict[myDr] = matchedQuark.momentum().mag()/1000
            for dr,pt in DrPtDict.iteritems():
                self.hists["deltaR_cQuarkPt"].Fill(dr,pt)
                break 
            #Something is Wrong in the above statemetns.. Needs more investigation 

            '''check if the FourVector of quarks and hadrons match'''
            index_dict = dict([(self.fMECQuarkList.index(q),self.fCHadronList.index(h)) for q in self.fMECQuarkList for h  in self.fCHadronList \
                    if math.sqrt((q.momentum().eta() - h.momentum().eta())**2 + (q.momentum().phi() - h.momentum().phi())**2) < self.fDeltaRCut])

            if(len(index_dict)):
                '''Found A match'''
                FoundCMatch = True
                for q_idx, h_idx in index_dict.iteritems():
                    matchedQuark = self.fMECQuarkList[q_idx]
                    matchedHadron= self.fCHadronList[h_idx]
                    
                    self.hists["matched_cQuarkPt"].Fill(matchedQuark.momentum().perp()/1000)
                    self.hists["matched_cQuarkEta"].Fill(matchedQuark.momentum().eta())
                    self.hists["matched_cQuarkPhi"].Fill(matchedQuark.momentum().phi())
                    
                    self.hists["matched_cHadronPt"].Fill(matchedHadron.momentum().perp()/1000)
                    self.hists["matched_cHadronEta"].Fill(matchedHadron.momentum().eta())
                    self.hists["matched_cHadronPhi"].Fill(matchedHadron.momentum().phi())

                    endVertex = matchedHadron.end_vertex()
                    if(endVertex):
                        for daughter in self.toiter(endVertex.particles_begin(1),endVertex.particles_end(1)):
                            if(abs(daughter.pdg_id())==11 and daughter.status() ==1):
                                self.fCElectronlist += [daughter]
                                HasDaughterElectron= True

                
                self.hists["nCEventsGen"].Fill(1)
                if(HasDaughterElectron): 
                    self.hists["nCEventsSemileptGen"].Fill(1)
                    returnString = 'cbackground'

        else :
            returnString = "lightbackground"

        if(FoundBMatch):
            self.hists["nBEventsMatched"].Fill(1)
        elif(FoundCMatch):
            self.hists["nCEventsMatched"].Fill(1)
        elif(FoundBMatch and FoundCMatch):
            print "Found Both B And C Match in the event: FATAL"

        return returnString


    '''Iteratre Over the particles in 
    GenEvent Container'''
    def execute(self,ev):

        self.ResetCounters()
        eventType = self.EventType(ev)
        nSoftElectrons  = len(self.fSoftElectrons)
        nHardElectrons  = len(self.fHardElectrons)
          
        nElectrons      = nSoftElectrons + nHardElectrons
        self.hists["nEl"].Fill(nElectrons)
        self.hists["nHardEl"].Fill(nHardElectrons)
        self.hists["nSoftEl"].Fill(nSoftElectrons)

        '''Semi leptonic decay electron '''
        [self.hists["bElectronPt"].Fill(el.momentum().perp()/1000) for el in self.fBElectronlist]
        [self.hists["cElectronPt"].Fill(el.momentum().perp()/1001) for el in self.fCElectronlist]

        [self.hists["bElectronEta"].Fill(el.momentum().eta()) for el in self.fBElectronlist]
        [self.hists["cElectronEta"].Fill(el.momentum().eta()) for el in self.fCElectronlist]

        [self.hists["bElectronPhi"].Fill(el.momentum().phi()) for el in self.fBElectronlist]
        [self.hists["cElectronPhi"].Fill(el.momentum().phi()) for el in self.fCElectronlist]


        if(eventType == "signal"):
            self.hists["nHardElSignal"].Fill(nHardElectrons)
            self.hists["nSoftElSignal"].Fill(nSoftElectrons)

            if(nElectrons ==3):
                '''Three prong'''
                self.hists["nBEventsThreeProngAccptd"].Fill(1) 
                if(nHardElectrons==2 and nSoftElectrons==1):
                    self.hists["nBEventsTwoAndOneAccptd"].Fill(1)
                    if(len([(p,q) for p in self.fSoftElectrons for q in self.fBElectronlist if p.barcode() == q.barcode()])):
                        self.hists["nBEventsTrueThreeProng"].Fill(1)


            elif(nElectrons ==4):
                self.hists["nBEventsFourProngAccptd"].Fill(1)
                '''Four Prong'''
                if(nHardElectrons==2 and nSoftElectrons ==2):
                    self.hists["nBEventsTwoAndTwoAccptd"].Fill(1)
        
        elif(eventType == "cbackground"):
            self.hists["nHardElBkgrnd"].Fill(nHardElectrons)
            self.hists["nSoftElBkgrnd"].Fill(nSoftElectrons)

            '''Three Prong'''
            if(nElectrons ==3):
                self.hists["nCEventsThreeProngAccptd"].Fill(1) 
                if(nHardElectrons==2 and nSoftElectrons==1): 
                    self.hists["nCEventsTwoAndOneAccptd"].Fill(1)
                    if(len([(p,q) for p in self.fSoftElectrons for q in self.fCElectronlist if p.barcode() == q.barcode()])):
                        self.hists["nCEventsTrueThreeProng"].Fill(1)
                    
            elif(nElectrons ==4):
                self.hists["nCEventsFourProngAccptd"].Fill(1)
                '''Four Prong'''
                if(nHardElectrons==2 and nSoftElectrons==2):
                    self.hists["nCEventsTwoAndTwoAccptd"].Fill(1)

        elif(eventType=="lightbackground"):
            if(nElectrons ==3):
                self.hists["nOtherEventsThreeProngAccptd"].Fill(1)
                if(nHardElectrons ==2 and nSoftElectrons ==1):
                    self.hists["nOtherEventsTwoAndOneAccptd"].Fill(1)

            elif( nElectrons ==4):
                self.hists["nOtherEventsFourProngAccptd"].Fill(1)
                if(nHardElectrons ==2 and nSoftElectrons ==2):
                    self.hists["nOtherEventsTwoAndTwoAccptd"].Fill(1)

    '''Getters'''
    def GetNBEvents(self):
        return float(self.hists["nBEventsGen"].Integral())
    
    def GetNBEventsSemileptonic(self):
        return float(self.hists["nBEventsSemileptGen"].Integral())

    def GetNCEvents(self):
        return float(self.hists["nCEventsGen"].Integral())

    def GetNCEventsSemileptonic(self):
        return float(self.hists["nCEventsSemileptGen"].Integral())

    def finalize(self):
        f = ROOT.TFile("output.root","RECREATE")
        [object.Write() for name,object in self.hists.iteritems()]
        f.Close()
            
                                 
####################End of SoftElectron Class ########################
